import java.util.Collection;

/**
 * This is a circular, singly linked list.
 */
public class LinkedList<E> implements List<E> {

	protected Node<E> head;

	protected int size;

	@Override
	public void add(E e) {
		Node<E> curr = head;
		if (curr==null){
			head = new Node<E>(e);
			head.setNext(head);}
		else {
			while (curr.getNext() != head)
				curr = curr.getNext();
			curr.setNext(new Node<E>(e));
			curr.getNext().setNext(head);}
		size++;}

	/*
	 * You will want to look at Iterator, Iterable, and 
	 * how to use a for-each loop for this method.
	 */
	@Override
	public void addAll(Collection<? extends E> c) {
		for(E item: c) add(item);}

	@Override
	public void clear() {
		head = null;
		size=0;}

	@Override
	public boolean contains(Object o) {
		if (indexOf(o)>=0) return true;
		return false;}

	@Override
	public E get(int index) {
		Node<E> curr = head;
		if (index<size){
			for (int i=0;i<index;i++) curr = curr.getNext();
			return curr.getData();}
		else return null;}

	@Override
	public int indexOf(Object o) {
		Node<E> curr = head;
		int count = 0;
		while (curr.getNext()!=head){
			if (curr.getData().equals(o)) return count;
			count++;
			curr = curr.getNext();}
		if (curr.getData().equals(o)) return count;
		return -1;}

	@Override
	public boolean isEmpty() {
		return size==0;}

	@Override
	public E remove(int index) {
		Node<E> curr = head;
		Node<E> temp = null;
		if (index==0){
			if (size>1){
				temp = head;
				while (curr.getNext()!=head) curr = curr.getNext();
				head = head.getNext();
				curr.setNext(head);}
			else{
				temp = head;
				clear();}		}
		else{
			for (int i=1;i<index;i++)
				curr = curr.getNext();
			temp = curr.getNext();
			curr.setNext(curr.getNext().getNext());}
		size--;
		return temp.getData();}

	@Override
	public E remove(Object o) {
		if (indexOf(o) == -1) return null;
		return remove(indexOf(o));}

	@Override
	public E set(int index, E e) {
		Node<E> curr = head;
		Node<E> temp = null;
		if (index==0){
			if (size>1){
				temp = head;
				for (int i=0;i<(size-1);i++) curr = curr.getNext(); 
					head = new Node<E>(e);
					head.setNext(temp.getNext());
					curr.setNext(head);}
			else {
				temp = head;
				clear();
				add(e);}}
		else {
		for (int i=0;i<index-1;i++) curr = curr.getNext();
		temp = curr.getNext();
		curr.setNext(new Node<E>(e));
		curr.getNext().setNext(temp.getNext());}
		return temp.getData();}

	@Override
	public int size() {
		return size;}

	/*
	 * The following methods are for grading. Do not modify them, and do not use them.
	 */

	public void setSize(int size) {
		this.size = size;}

	public Node<E> getHead() {
		return head;}

	public void setHead(Node<E> head) {
		this.head = head;}
}
